#include "udpclient.h"
#include <QtNetwork/QUdpSocket>
// #include <QtNetwork/QTcpServer>
#include <QtNetwork/QTcpSocket>
#include <QtNetwork/QHostAddress>
#include "udpsys.h"
#include "cmdthread.h"
#include "sysinfo.h"
#include <iostream>
#include <QStringList>
using namespace std;

///
/// \brief UdpClient::UdpClient 构造函数
/// \param parent
///
UdpClient::UdpClient(QObject *parent) : QObject(parent)
{
    QUdpSocket *udpsocket_1 = new QUdpSocket(this);
    QUdpSocket *udpsocket_2 = new QUdpSocket(this);
    sysinfo                 = new SysInfo;
    this->udpsocket = udpsocket_1;
    this->socket_port = PORT_UDP_COMM_1;

    bool result = udpsocket_1->bind(PORT_UDP_COMM_1);
    if(!result){
        cout << "udpsocket_1 bind-" << PORT_UDP_COMM_1 << " error!" << endl;
        result = udpsocket_2->bind(PORT_UDP_COMM_2);
        if(!result){
            cout << "udpsocket_2 bind-" << PORT_UDP_COMM_2 << " error!" << endl;
        }else{
            this->udpsocket = udpsocket_2;
            this->socket_port = PORT_UDP_COMM_2;
            cout << "udpsocket_2 bind-" << PORT_UDP_COMM_2 << " success!" << endl;
            connect(udpsocket, SIGNAL(readyRead()), this, SLOT(dataReceived_socket_2()));
        }
    }else{
        cout << "udpsocket_1 bind-" << PORT_UDP_COMM_1 << " success!" << endl;
        connect(udpsocket, SIGNAL(readyRead()), this, SLOT(dataReceived_socket_1()));
    }

    tcpsocket = NULL;
}

UdpClient::~UdpClient()
{
    onTcpserver_disConnect();
}

void UdpClient::dataReceived_socket_1()
{
    processUdpData(PORT_UDP_COMM_1);
}

void UdpClient::dataReceived_socket_2()
{
    processUdpData(PORT_UDP_COMM_2);
}

void UdpClient::onTcpserver_newConnect()
{
    qDebug() << "与服务器连接成功, client: " << tcpsocket;
}

void UdpClient::onTcpserver_dataReceived()
{
    processTcpData();
}

void UdpClient::onTcpserver_disConnect()
{
    if(tcpsocket != NULL){
        qDebug() << "与服务器断开连接, client: " << tcpsocket;
        tcpsocket->close();
        tcpsocket->deleteLater();
        // delete tcpsocket;
        tcpsocket = NULL;
    }
}

void UdpClient::onCmdStatChanged(QString cmdstr, int stat)
{
    CmdThread* cmdThread = qobject_cast<CmdThread*>(sender());
    QString outstr = "";
    int cmdid = 0;
    switch (stat) {
    case CmdThread::CMD_RUNING:         //命令在运行，有输出返回
        outstr = cmdThread->GetCmdOutstr();
        cmdid = CMD_RUNCMD;
        break;
    case CmdThread::CMD_TIMEOUT:        //命令运行超时（服务端设定的超时时间）
        cmdid = CMD_OUTCMD;
        break;
    case CmdThread::CMD_END:            //命令运行结束
        cmdid = CMD_ENDCMD;
        cmdThread->disconnect();
        cmdThreadList.removeOne(cmdThread);
        break;
    case CmdThread::CMD_CRASHEND:       //命令行运行异常结束
        cmdid = CMD_ERREND;
        outstr = cmdThread->GetErrstr();
        cmdThread->disconnect();
        cmdThreadList.removeOne(cmdThread);
        break;
    default:
        cmdid = CMD_ERREND;
        break;
    }

    bool sendOk = true;
    if(tcpsocket != NULL){
        int lengths = outstr.length();
        int len_sin = lengths;
        // 拆包，使得每帧都小于MTU
        for(int i=0; i<lengths/1024+1; i++){
            if(!UdpSys::sendDataGram_toAddress(tcpsocket, cmdThread->GetHostIP(),
                                              cmdid, cmdThread->GetRumTimes(), cmdstr, outstr.mid(i*1024, len_sin>1024?1024:len_sin%1024)) ){
                sendOk = false;
            }
            len_sin -= 1024;
        }
    }
    if(false == sendOk){
        int lengths = outstr.length();
        int len_sin = lengths;
        // 拆包，使得每帧都小于MTU
        for(int i=0; i<lengths/1024+1; i++){
            UdpSys::sendDataGram_toAddress(udpsocket, this->socket_port, cmdThread->GetHostIP(),
                                           cmdid, cmdThread->GetRumTimes(), cmdstr, outstr.mid(i*1024, len_sin>1024?1024:len_sin%1024) );
            len_sin -= 1024;
        }
    }
}

void UdpClient::processUdpData(int port_comm)
{
    static QString hostIPStr_last = "";
    QHostAddress hostAddress;
    quint16 hostPort;
    QString ipstr;

    while(udpsocket->hasPendingDatagrams()){
        QByteArray datagram;
        datagram.resize(static_cast<int>(udpsocket->pendingDatagramSize()));

        udpsocket->readDatagram(datagram.data(), datagram.size(), &hostAddress, &hostPort);
        QByteArray dataStr = UdpSys::getDataRecvShow(datagram).toLatin1();

        QByteArray address = UdpSys::getHostIP(hostAddress).toLatin1();
        ipstr = address.data();

        if(0 != hostIPStr_last.compare(ipstr)){                         // hostIP更换了，重新连接服务器
            hostIPStr_last = ipstr;
            cout << "recvData: " << dataStr.data() << endl;
            cout << "hostAddr: " << address.data() << endl;
            cout << "hostPort: " << hostPort << endl;
        }

        if(tcpsocket == NULL || tcpsocket->peerAddress() == QHostAddress::Null){
            cout << "try connect tcpserver: " << address.data() << ", port: " << PORT_TCP_COMM_1 << endl;
            onTcpserver_disConnect();
            tcpsocket = new QTcpSocket();
            tcpsocket->connectToHost(ipstr, PORT_TCP_COMM_1);
            connect(tcpsocket, SIGNAL(connected()), this, SLOT(onTcpserver_newConnect()));
            connect(tcpsocket, SIGNAL(readyRead()), this, SLOT(onTcpserver_dataReceived()));
            connect(tcpsocket, SIGNAL(disconnected()), this, SLOT(onTcpserver_disConnect()));
        }
        processRecvData(datagram, hostAddress, port_comm);
    }
}

void UdpClient::processTcpData()
{
    if(tcpsocket == NULL){
        return;
    }
    QByteArray datagram = tcpsocket->readAll();
    QHostAddress hostAddress = tcpsocket->peerAddress();
    processRecvData(datagram, hostAddress, PORT_UDP_COMM_1);
}

void UdpClient::processRecvData(QByteArray &datagram, QHostAddress &hostAddress, int port_comm)
{
    QStringList macList;
    QString sendStr, cmdstr;
    QByteArray debugDatagram;
    CmdThread *cmdThread = NULL;
    QByteArray address = UdpSys::getHostIP(hostAddress).toLatin1();

    int order = UdpSys::getOrder(datagram);
    switch (order) {
    case CMD_STATUS:                                            // 获取设备状态信息
        macList = UdpSys::getLocalMacAddress();
        for(int i=0; i<macList.length(); i++){
            sendStr.append(macList.at(i));
        }

        UdpSys::sendDevState_toAddress(udpsocket, port_comm,  UdpSys::getHostIP(hostAddress),
                                           sysinfo->cpuRate, sysinfo->memRate, sysinfo->cpuTemp, sysinfo->vdoTemp, sysinfo->hddTemp,sendStr);
        break;
    case CMD_RUNCMD:                                            // 执行命令
        /* 检测命令是否为空 */
        cmdstr = UdpSys::getCmdStr(datagram);
        if(cmdstr.length() <= 0){
            cout << "Err: cmdstr len is 0!!!" << endl;
            return;
        }
        /* 检测命令是否已经在执行 */
        for(int i=0; i<cmdThreadList.length(); i++){
            if(0 == cmdThreadList.at(i)->GetCmdstr().compare(cmdstr, Qt::CaseSensitive)){
                debugDatagram = QString("Warning: cmd<%1> alread runing!").arg(cmdstr).toLatin1();
                cout << debugDatagram.data() << endl;
                return;
            }
        }
        cout << "Start run '" << cmdstr.data() << "', fromIP: " << address.data()
             << ", time: " << QDateTime::currentDateTime().toString("yyyy-M-d h:m:s").data() << endl;
        /* 开始执行命令 */
        cmdThread = new CmdThread(cmdstr, UdpSys::getTimes(datagram), UdpSys::getHostIP(hostAddress));
        cmdThreadList.append(cmdThread);
        connect(cmdThread, SIGNAL(cmdStatChanged(QString,int)), this, SLOT(onCmdStatChanged(QString,int)), Qt::QueuedConnection);
        cmdThread->start();
        break;
    case CMD_KILLALL:
        for(int i=0; i<cmdThreadList.length(); i++){
            cmdThreadList.at(i)->killRun();
        }
        break;
    default:
        break;
    }
}

